package motifs;

import static com.googlecode.javacv.cpp.opencv_highgui.cvLoadImage;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import package_traitement.MatriceTonGris;

import com.googlecode.javacv.cpp.opencv_core.IplImage;

/**
 * classe representant une des images a traiter, avec les descripteurs souhaites
 * @author Alexandre Masson
 *
 */
public class ImageATraiter {
	private String nomFichier ;
	private String PATH;
	private String OUT_PATH;
	public static final int [] FOUR_DIR_ANGLES = {0,90,180,270};
	public static final int FOUR_DIR_SIZE = 4;
	public static final int [] EIGHT_DIR_ANGLES = {0,45,90,135,180,225,270,315};
	public static final int EIGHT_DIR_SIZE = 8;
	public static final int NIVEAUX_GRIS = 16;
	private BufferedImage image;
	private int [] lesAngles ;
	private int AnglesSize;
	private int pas_max;
	private ArrayList<Empreinte> lesEmpreintes;

	/**
	 * Constructeur de la classe ImageATraiter
	 * 
	 * @param in_path
	 * 				- le chemin du dossier d'entree
	 * 
	 * @param out_path
	 * 				- le chemin du dossier de sortie pour les resultats
	 * 
	 * @param filename
	 * 				- nom du fichier de l'image
	 * 
	 * @param p
	 * 				- pas maximum sur lequel traiter les images.
	 * 
	 * @param tabAngles
	 * 				- tableau d'entiers qui contient les angles à traiter pour les futures cooccurrences
	 * 
	 * @param anglesSize
	 * 				- taille du tableau tabAngles
	 */
	public ImageATraiter(String in_path,String out_path, String filename , int  p, int [] tabAngles, int anglesSize){	
		//setImage(i);
		PATH = in_path;
		OUT_PATH = out_path;
		nomFichier = filename;
		IplImage i = cvLoadImage(PATH+filename,0);
		lesAngles = tabAngles;
		AnglesSize = anglesSize;

		if(i != null){
			image = i.getBufferedImage();
			pas_max = p;
			image = cropImage(image,Color.WHITE);
			new MatriceTonGris(image);
			genEmpreinte(new Color(206,206,206));
			
			//System.out.println("IAT cree");
		}
	}

	/**
	 * Methode qui genere les empreintes qui composent l'image.
	 * 
	 * @param seuil
	 * 				- niveau de gris pour retrouver les parties de l'image.
	 */
	private void genEmpreinte(Color seuil) {
		int compteur = 0;
		// copie reelle de a bufferredIMage
		BufferedImage process =  new BufferedImage(
				image.getWidth(),
				image.getHeight(),
				image.getType());

		Graphics g = process.createGraphics();
		g.drawImage(image,0,0,null);
		g.dispose();
		lesEmpreintes = new ArrayList<Empreinte>();
		//on parcours toute l'image process, pour trouver les coins hauts-gauches des empreintes
		for(int i =0;i< process.getWidth();i++){
			for(int j = 0; j < process.getHeight() ; j++ ){
				if((new Color(process.getRGB(i, j)).getRGB() <= seuil.getRGB())){
					//on appelle la methode qui va decouper l'empreinte et creer la nouvelle
					BufferedImage res = new BufferedImage(process.getWidth(), process.getHeight(), process.getType());
					for(int ii = 0; ii< res.getWidth(); ii++){
						for( int kk =0 ;kk< res.getHeight() ; kk++){
							res.setRGB(ii, kk, Color.WHITE.getRGB());
						}
					}
					decoupEmpreinte(process,res,i,j,seuil);
					//res contient une image non coupee du motif seul, on la crop
					res = cropImage(res, Color.white);
					//on ajoute l'empreinte a la liste
					lesEmpreintes.add(new Empreinte(res,OUT_PATH+nomFichier+compteur+".jpg",PATH+nomFichier, lesAngles, AnglesSize, pas_max));
					compteur++;

				}
			}
		}
		//System.out.println("Empreinte cree");
		//System.out.println("nb empreintes : "+ lesEmpreintes.size());
	}

	/**
	 * Methode qui une fois qu'on a trouver le coin d'une empreinte, recupere le reste dans une image
	 * 
	 * @param orig
	 * 			- BufferedImage d'origine.
	 * 
	 * @param res
	 * 			- BufferedImage de sortie.
	 * 
	 * @param x
	 * 			- abscisse du pixel decouvert pour l'empreinte.
	 * 
	 * @param y
	 * 			- ordonnee du pixel decouvert pour l(empreinte.
	 * 
	 * @param seuil
	 * 			- niveau pour lequel on considere un pixel valide pour l'empreinte.
	 */
	private void decoupEmpreinte( BufferedImage orig, BufferedImage res, int x, int y, Color seuil){
		if((new Color(orig.getRGB(x, y)).getRGB() <= seuil.getRGB()  )){
			//on recopie le motif dans res, et on efface dans orig
			res.setRGB(x, y, orig.getRGB(x, y));
			orig.setRGB(x, y, Color.WHITE.getRGB());
			//on appelle dans toutes les direction, en verifiant que le pixels n'est pas deja blanc dans origine
			//haut gauche
			if( y >= 1){	
				if(x>=1){
					if(orig.getRGB(x-1, y-1) <= seuil.getRGB()){
						decoupEmpreinte(orig, res, x-1, y-1, seuil);
					}
				}
				//haut
				if(orig.getRGB(x, y-1) <= seuil.getRGB()){
					decoupEmpreinte(orig, res, x, y-1,seuil);
				}
				//haut droite
				if(x< orig.getWidth()-1){	
					if(orig.getRGB(x+1, y-1) <= seuil.getRGB()  ){
						decoupEmpreinte(orig, res, x+1, y-1, seuil);
					}
				}
			}
			//gauche
			if(x>=1){
				if(orig.getRGB(x-1, y) <= seuil.getRGB() ){
					decoupEmpreinte(orig, res, x-1, y,seuil);
				}
			}
			//droite
			if(x < orig.getWidth()-1){
				if(orig.getRGB(x+1, y) <= seuil.getRGB() ){
					decoupEmpreinte(orig, res, x+1, y,seuil);
				}
			}
			if( y < orig.getHeight() -1){	
				//bas gauche
				if(x>=1){
					if(orig.getRGB(x-1, y+1) <= seuil.getRGB()  ){
						decoupEmpreinte(orig, res, x-1, y+1,seuil);
					}
				}
				//bas
				if(orig.getRGB(x, y+1) <= seuil.getRGB() ){
					decoupEmpreinte(orig, res, x, y+1,seuil);
				}
				//bas droite
				if(x<orig.getWidth()-1){
					if(orig.getRGB(x+1, y+1) <= seuil.getRGB()  ){
						decoupEmpreinte(orig, res, x+1, y+1,seuil);
					}
				}
			}
		}
	}


	/**
	 * Fonction qui permet de decouper une image afin de supprimer le tour.
	 * 
	 * @param image
	 * 			- BufferredImage à decouper.
	 * 
	 * @param fond
	 * 			- Color de fond a supprimer.
	 * 
	 * @return
	 * 			- BufferredImage.getSubimage de image , mais sans le tour.
	 */
	public BufferedImage cropImage(BufferedImage image,Color fond){
		int g = 0,h = 0;
		int d = image.getWidth();
		int b = image.getHeight();
		boolean trouvH = false,trouvB = false ,trouvG = false ,trouvD = false;
		int width = image.getWidth();
		int height = image.getHeight();
		//parcours horizontal pour trouver haut
		for(int im = 0; im < height && !trouvH ;im++){
			for(int j = 0; j< width && !trouvH; j++){
				if(!(new Color(image.getRGB(j, im )).equals(fond))){
					trouvH = true;
					h = im;		
				}
			}
		}

		//parcours horizontal pour trouver le bas
		for(int im = height-1; im >= 0 && !trouvB ; im-- ){
			for(int j = 0; j < width && !trouvB ; j++){
				if(!(new Color(image.getRGB(j,im)).equals(fond))){
					trouvB = true;
					b = im;		
				}
			}
		}

		//parcours vertical pour trouver gauche
		for(int m = 0 ; m< width && !trouvG; m++){
			for(int j= 0 ; j < height && !trouvG  ;j++){
				if(!(new Color(image.getRGB(m,j)).equals(fond))){
					trouvG = true;
					g = m;
				}
			}
		}

		//parcours vertical pour trouver droite
		for(int m = width-1 ; m >= 0 && !trouvD; m--){
			for(int j= 0 ; j < height && !trouvD  ;j++){
				if(!(new Color(image.getRGB(m, j)).equals(fond))){
					trouvD = true;
					d = m;
				}
			}
		}
		if(d-g > 0 && b-h >0){
			return image.getSubimage(g, h, d-g, b-h);
		}
		else return image;
	}

	public void setImage(BufferedImage image) {
		this.image = image;
	}

	public BufferedImage getImage() {
		return image;
	}

	

	public ArrayList<Empreinte> getLesEmpruntes() {
	
		return lesEmpreintes;
	}
	
	/**
	 * Fonction qui permet de recuperer les histogramme linearises dans une chaine de caracteres
	 * 
	 * @return
	 * 		- un chaine qui contient les histogrammes simple,double,et triple, mais dans une seule ligne
	 */
	public String getLinearHistograms(){
		StringBuffer sbuf = new StringBuffer();
		for(int  i = 0 ; i < lesEmpreintes.size(); i++){
			sbuf.append(lesEmpreintes.get(i).getLinearHistograms());
			sbuf.append(';');
			sbuf.append('\n');
		}
		
		return sbuf.toString();
	}

	/**
	 * Fonction pour parser l'ImageATraiter en String , pour affichage ou sauvegarde.
	 */
	public String toString(){
		StringBuffer sbuf = new StringBuffer();
		
		for(int e = 0; e< lesEmpreintes.size(); e++){
			sbuf.append(lesEmpreintes.get(e).toString());
			sbuf.append(';');
			sbuf.append('\n');
		}

		return sbuf.toString();
	}

}
